//在该文件夹下的 编写ws指令.txt 编写ws能够直接执行的原语，然后由该程序读取，并在控制台输出结果
//很简陋，也有很多可优化的地方，欢迎大家提出更好的建议
/*
指令格式：指令(mov、add…)(4位)，修饰（1位），输入地址(8位)，修饰符(2位)，输入(8位)
指令编码：
mov    0001
add    0010
sub    0011
right  0100
equal  0101
than   0110
not    0111
or     1000
and    1001
xor    1010
print  1011
scanf  1100
if     1101
esc    1110
random 1111
*/

/*
 * 更新日志：
 *  主要功能已完工
 *  2022/11/16 修复了记事本最后一行指令读取问题
 *  2022/11/17 更改了print指令的输出为"输入"
 *  2022/11/17 修复了equal、than的bug
 *  2022/11/17 修复了scanf指令的bug（所有指令的测试都通过！）
 *  2022/11/18 修改了指令退出的机制
 *  2022/11/25 vector<int> Code优化开工，代码读取部分已无问题
 *  2022/11/26 新增bineryPrint函数，vector<int>优化完工
 *  2022/11/26 重置了print指令，把else if改为了switch
 *  2022/11/27 新增了random指令，所以指令全部填满了
 *  2022/12/02 新增输出寄存器
 *  2022/12/04 更改了输出寄存器的输出顺序，增加了输出寄存器的地址显示
 *  2022/12/04 新增了1个SyntaxError，1个IndexError与2个warning，更新了bineryPrint
 *  2022/12/05 修复了记事本空行的问题，优化了警告与报错
 *  2022/12/12 当address大于127时为输出字符模式
 *  2022/12/15 新增1syntaxError，将地址改为全英文以增加安全性
 */

#include <iostream>
#include <vector>
#include <ctime>
#include <math.h>

#define ADDRESS "D:\\MyProjects\\Physics_Lab_Language\\wushi\\Codes\\WriteWushi.txt" //默认该记事本中的指令及格式皆正确
#define PRINT_MEM_SIZE 4

#define DEBUG 0

using namespace std;

bool mem_print(unsigned char, unsigned char, int);//打印一个unsigned char
void debugPrint(int);       //传入一个数，打印出其二进制形式
                              //开辟一块大小为256的内存，用来实现实验中的内存原件的功能
unsigned char mem[256] = {0}; //mem就相当于实验中的内存  
int codes_address = 0;        //代码的地址的寄存器
                              //codes相当于实验中用来存储代码的内存
vector<int> Codes;            //将原本用于存储指令的字符串换为int进行存储
vector<int> 
    print_mem(PRINT_MEM_SIZE);//输出寄存器

int main()
{
    FILE* file;
    file = fopen(ADDRESS, "r");

    if(file == NULL) {
        puts("OpenFileError: Failed to open the file.\n");
        return 0;
    }
    {
        //文件读取成功
        bool enter = true; //记录记事本中的回车键，true为可以输入回车键，防止连续回车的问题
        unsigned char i_code = 0; //向code中写入数据时的下标
        unsigned char code_char = 0, mem_code_char = 0;
        int Code = 0; //将原本用于存储指令的字符串换为int进行存储
        bool error = false; //是否报错

        int lock1 = -1;

        while ( true )
        {
            mem_code_char = code_char;
            code_char = fgetc(file);


            //结束读取指令
            if( feof(file) ) {
                if ( mem_code_char != '\n' ) {
                    Codes.push_back(Code);
                }
                break;
            }
            //输入字符不合法
            else if (code_char != '0' && code_char != '1' && code_char != ' ' && code_char != '\n') {
                cout << "line " << Codes.size() << " : " << "SyntaxError: '" << code_char << "' not a valid character like '0', '1', ' '." << endl;
                //return 0;
                error = true,
                i_code = code_char != '\n'? i_code + 1: 0;
                continue;
            }
            //指令长度超过规定长度
            if (i_code > 27) {
                if (i_code == 28) Codes.push_back(Code);
                if (lock1 != Codes.size()) {
                    cout << "line " << Codes.size() - 1 << " : " << "warning: The length of the instruction must be less than 28." << endl;
                    lock1 = Codes.size();
                } i_code = code_char != '\n'? i_code + 1: 0;
                continue;
            }
            //出现其他字符
            if (i_code == 4 || i_code == 6 || i_code == 15 || i_code == 18) {
                if (code_char != ' ' && code_char != '\n') {
                    cout << "line " << Codes.size() << " : " << "warning: ' ' is replaced by other characters." << endl;
                }
            }else if (i_code < 27) {
				if (code_char != '0' && code_char != '1') {
				    cout << "line " << Codes.size() << " : " << "syntaxError: Expect a 0 or 1 but accept some other character." << endl;
					return 0;
				}
			}

            //写入指令
            if (code_char != '\n')
            {
                enter = true;
                if (code_char - '0' && code_char != ' ') {
                    Code |= 1 << i_code;
                }
                else {
                    Code &= 2147483647 - (1 << i_code);
                }
                ++i_code;
            }
            else if (code_char == '\n' && enter)
            {
                i_code = 0, enter = false;
                Codes.push_back(Code);
            }else if (enter == false) {
                Codes.push_back(0);
            }
        }
        if (error) {
            return 0;
        }
    }
#if (DEBUG == 1)
    //测试代码，用于输出vector<string> codes
    for(int i = 0; i < Codes.size(); ++i) {
        debugPrint( i );
    }
#endif
    //记事本中的指令已被全部写入向量codes中。
    srand((unsigned int)time(NULL));
    while ( true )
    {
        // vector<int> Code重置执行代码
        //解析"指令"
        int Code = Codes.at(codes_address); 
        unsigned char cmd = 0, i = 0;
        for (i = 0; i < 4; ++i) {
            cmd += (bool)(Code & (1 << i)) << (3 - i);
        }
        //解析"修饰+输入地址"
        unsigned char address = 0;
        bool sign1 = (bool)( Code & 16 );
        for (i = 7; i < 15; ++i) {
            address += (bool)(Code & (1 << i)) << (14 - i);
        }
        if (sign1) {
            address = mem[address];
        }
        //解析"修饰符+输入"
          unsigned char inputs = 0, sign2 = 0;
        for (i = 19; i < 27; ++i) {
            inputs += (bool)(Code & (1 << i)) << (26 - i);
        }
        if ((Code & (1 << 17))) ++sign2;
        if ((Code & (1 << 16))) sign2 += 2;
        if (sign2 == 1) inputs = mem[inputs];
        else if (sign2 == 2) inputs = mem[mem[inputs]];

        //执行指令
        switch(cmd)
        {
        case 1:   mem[address] =   inputs;                   break; // mov
        case 2:   mem[address] +=  inputs;                   break; // add
        case 3:   mem[address] -=  inputs;                   break; // sub
        case 4:   mem[address] >>= 1;                        break; // right
        case 5:   mem[0]       =   mem[address] == inputs;   break; // equal
        case 6:   mem[0]       =   mem[address] >  inputs;   break; // than
        case 7:   mem[address] =   ~(mem[address] | inputs); break; // not
        case 8:   mem[address] |=  inputs;                   break; // or
        case 9:   mem[address] &=  inputs;                   break; // and
        case 10:  mem[address] ^=  inputs;                   break; // xor
        case 11:  if(mem_print(address, inputs, codes_address)) {   // print
                      return 0;                
                  }break;                                            
        case 12:  cout << "Enter a number between 0 and 255: ";
                  scanf("%d", mem + address);                break; // scanf
        case 13:  if (inputs & 1 == 1)
                      codes_address = address - 1;           break; // if
        case 14:  fclose(file); return 0;                           // esc
        case 15:  mem[address] =   rand() % 256;
        }

        ++codes_address;
        if ( codes_address == Codes.size() ) {
            codes_address = 0;
        }
    }

    return 0;
}

#if (DEBUG == 1)
void debugPrint(int i) //传入一个数，打印出其二进制形式
{
    int num = Codes.at(i);
    cout << ">>> " << i << " : ";
    char j = 27;
    while (j) {
        cout << (bool)(num & 1);
        num /= 2;
        --j;
    }
    cout << endl;
}
#endif

bool mem_print(unsigned char address, unsigned char inputs, int codes_address) //print指令，输出寄存器address，输出的值inputs，指令行数codes_address
{
    if (address > 127) {
        printf("%c", inputs);
        print_mem.at(address % 128) = inputs;
        return false;
    }

    if (address >= PRINT_MEM_SIZE) {
        cout << "line " << codes_address << " : " << "IndexError: The address of the output register is less than " << PRINT_MEM_SIZE << "." << endl;
        return true;
    }

    print_mem.at(address) = inputs;
    for (char k = PRINT_MEM_SIZE - 1; k != -1; --k)
    {
        if(k < 16) cout << 0;
        printf("%x: ", k);
        inputs = print_mem.at(k);
        unsigned char result[8] = {0};
        char i = 7;
        while (inputs) {
            result[i--] = inputs & 1,
            inputs >>= 1;
        }
        for (char j = 0; j != 8; ++j) {
            cout << (bool)result[j];
        }cout << endl;
    }cout << endl;
    return false;
}
